home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Linux Cubed Series 8: LINUX Games
/
Linux Cubed Series 8 - LINUX Games.iso
/
games
/
x11
/
strategy
/
connx-1.001
/
connx-1~
/
xconnect.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-02-11
|
26KB
|
1,010 lines
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xos.h>
#include <X11/Xatom.h>
#include <X11/Xresource.h>
#include <pwd.h>
#include "xconnect.h"
#include "connect.h"
#ifdef DEBUG
#define PRINTF(x) printf x
#else
#define PRINTF(x)
#endif
/* the globals */
Pixmap pix;
Pixmap erase_circ;
Window win;
Display *display;
int screen_num;
GC open_text, draw_board, clear_board, draw_text, draw_circ, draw_shadow;
int width, height, block_width, block_height, line_width;
int player_pixels[MAX_PLAYERS];
XFontStruct *the_font;
board the_board;
extern char *program_name;
XrmDatabase dbase;
int game_winner;
coord win_start, win_end;
int game_over = False;
int players_turn;
game_start game_attrib;
int allocated = False;
/* some common colors */
int highlight, background, foreground, shadow;
/*prototypes*/
void make_board ();
void create_pixmaps ();
void create_gcs ();
void set_block_size ();
void resize (int w, int h);
void free_pixmaps ();
void free_gcs ();
void draw_piece (int row, int col, int pixel);
void change_color (int fg, int bg, GC change);
void draw_move (coord new_pos, coord old_pos);
int get_color (char *name);
char *get_resource (char *resource);
coord get_cursor_pos (int x, int y);
void get_home_dir (char *dest);
void list_players ();
void load_font ();
void draw_final ();
void draw_clock (time_t tleft);
/***************************************************************************/
/*MAIN ROUTINES************************************************************/
/*************************************************************************/
/*
* open the display and window
*/
int
X_open (char *pDisplay_name)
{
XGCValues gc_values;
char xdef[256];
XrmDatabase dbase_temp;
XTextProperty win_name;
/* connect to server */
if ((display = XOpenDisplay (pDisplay_name)) == NULL)
{
printf ("Cannot connect to X Server: %s\n", pDisplay_name);
return -1;
}
screen_num = DefaultScreen (display);
/* load resource file */
XrmInitialize ();
dbase = XrmGetFileDatabase (RESOURCE_FILE);
get_home_dir (xdef);
strcat (xdef, "/.Xdefaults");
dbase_temp = XrmGetFileDatabase (xdef);
XrmMergeDatabases (dbase_temp, &dbase);
highlight = get_color (get_resource ("highlight"));
foreground = get_color (get_resource ("foreground"));
background = get_color (get_resource ("background"));
shadow = get_color (get_resource ("shadow"));
/* open the window */
width = WIN_WIDTH;
height = WIN_HEIGHT;
win = XCreateSimpleWindow (display, RootWindow (display, screen_num),
X_WIN, Y_WIN, width, height, BORDER_WIDTH,
BlackPixel (display, screen_num),
background);
load_font ();
gc_values.foreground = foreground;
gc_values.graphics_exposures = False;
gc_values.font = the_font->fid;
open_text = XCreateGC (display, win, GCForeground | GCBackground |
GCFont | GCGraphicsExposures, &gc_values);
/* draw title on opening screen */
XDrawString (display, win, open_text, width / 2 - XTextWidth (the_font,
TITLE_STRING, strlen (TITLE_STRING)), height / 2, TITLE_STRING,
strlen (TITLE_STRING));
XStringListToTextProperty (&program_name, 1, &win_name);
XSetWMName (display, win, &win_name);
XMapWindow (display, win);
XSelectInput (display, win, ExposureMask | KeyPressMask
| StructureNotifyMask);
XFlush (display);
return 0;
}
/****************************************************************************/
/*
* close window and display
*/
int
X_close ()
{
XDestroyWindow (display, win);
XCloseDisplay (display);
return 0;
}
/****************************************************************************/
/*
* allocate resources and draw board
*/
int
X_allocate (game_start game_attr)
{
int i;
char resource[20];
if (allocated == True) /* deallocate resources from previous game */
X_deallocate ();
allocated = True;
/* set globals */
game_attrib = game_attr;
set_block_size ();
bzero (the_board, sizeof (board));
game_over = False;
players_turn = 1;
/* allocate player colors */
for (i = 0; i < game_attrib.num_players; i++)
{
sprintf (resource, "team%d", game_attrib.team_numbers[i]);
player_pixels[i] = get_color (get_resource (resource));
}
load_font ();
create_pixmaps ();
create_gcs ();
make_board ();
XFlush (display);
return 0;
}
/*****************************************************************************/
/*
* free resources used in game
*/
int
X_deallocate ()
{
if (allocated == True)
{
free_pixmaps ();
free_gcs ();
XFreeFont (display, the_font);
allocated = False;
return 0;
}
allocated = False;
}
/****************************************************************************/
/*
* get players move
*/
int
X_get_player_move (coord * move)
{
XEvent event;
int move_found = False;
Window root, child;
int root_x, root_y, win_x, win_y;
unsigned int buttons;
coord position;
coord new_pos;
coord null_move =
{-1, -1};
int cnt;
char buf[5];
KeySym keysym;
time_t the_time, time_left, old_time_left;
int rc = 0;
X_show_turn (game_attrib.your_number);
XSelectInput (display, win, ExposureMask | ButtonPressMask
| KeyPressMask | PointerMotionMask | StructureNotifyMask);
XQueryPointer (display, win, &root, &child, &root_x,
&root_y, &win_x, &win_y, &buttons);
change_color (player_pixels[game_attrib.your_number - 1], background,
draw_circ);
position = get_cursor_pos (win_x, win_y);
if (position.row != -1 && position.column != -1)
draw_move (position, null_move);
if (game_attrib.timeout != 0)
the_time = time (NULL);
while (move_found == False)
{
if (XPending (display) > 0)
{
XNextEvent (display, &event);
switch (event.type)
{
case KeyPress:
cnt = XLookupString (&event.xkey, buf, 1, &keysym, NULL);
if (buf[0] == 'q' || buf[0] == 'Q')
return QUIT;
break;
case ButtonPress:
*move = get_cursor_pos (event.xbutton.x, event.xbutton.y);
if (move->row != -1 && move->column != -1)
{
move_found = True;
move->row--;
move->column--;
draw_move (null_move, position);
if (game_attrib.timeout != 0)
draw_clock (-1);
}
break;
case MotionNotify:
new_pos = get_cursor_pos (event.xmotion.x, event.xmotion.y);
if (new_pos.row != -1
&& new_pos.column != -1 &&
((new_pos.row != position.row && game_attrib.game_type
== NOGRAVITY)
|| new_pos.column != position.column))
{
draw_move (new_pos, position);
position = new_pos;
}
break;
case Expose:
XCopyArea (display, pix, win, draw_board, event.xexpose.x,
event.xexpose.y, event.xexpose.width, event.xexpose.height,
event.xexpose.x, event.xexpose.y);
XFlush (display);
break;
case ConfigureNotify:
draw_move (null_move, position);
position.row = -1;
resize (event.xconfigure.width, event.xconfigure.height);
break;
default:
break;
}
}
/* check if server cancelled move*/
if (move_cancelled () == 1)
{
/* client sends forfeit message to server */
rc = FORFEIT;
move_found = True;
draw_move (null_move, position);
draw_clock (-1);
}
/* update timer indicating how mush time left to move*/
if (move_found == False && game_attrib.timeout != 0)
{
time_left = game_attrib.timeout - (time (NULL) - the_time);
if (time_left != old_time_left)
{
draw_clock (time_left);
old_time_left = time_left;
}
if (time_left <= 0)
{
/* client sends forfeit message to server */
rc = FORFEIT;
move_found = True;
draw_move (null_move, position);
draw_clock (-1);
}
}
}
XSelectInput (display, win, ExposureMask | StructureNotifyMask
| KeyPressMask);
return rc;
}
/**************************************************************************/
/*
* animate a piece moving into a position on the board
*/
int
X_add_to_board (coord move, int player_num)
{
int row_start;
int anim;
change_color (player_pixels[player_num - 1], background, draw_circ);
the_board[move.row][move.column] = player_num;
move.row++;
move.column++;
for (row_start = 0; row_start <= (move.row * block_height);
row_start = row_start + ANIM_PIXELS)
{
if (row_start != 0)
/* erase old circle */
XCopyArea (display, erase_circ, pix, draw_board, 0, 0,
block_width, block_height,
(move.column * block_width), row_start - ANIM_PIXELS);
/* save area */
XCopyArea (display, pix, erase_circ, draw_board,
(move.column * block_width),
row_start, block_width, block_height, 0, 0);
/* draw new circle */
XFillArc (display, pix, draw_circ, (move.column * block_width)
+ line_width / 2
,row_start + line_width / 2, block_width - line_width + 1,
block_height - line_width + 1, 0, 360 * 64);
/* draw line from board square */
XDrawLine (display, pix, draw_board, (move.column * block_width),
((row_start / block_height) + 1) * block_height,
(move.column + 1) * block_width,
((row_start / block_height) + 1) * block_height);
/* copy to window */
XCopyArea (display, pix, win, draw_board, (move.column * block_width),
row_start - ANIM_PIXELS,
block_width, block_height + ANIM_PIXELS,
(move.column * block_width), row_start - ANIM_PIXELS);
XFlush (display);
}
/* make sure piece lands in proper place */
row_start = row_start - ANIM_PIXELS;
anim = (move.row * block_height) - row_start;
if (anim != 0)
{
XCopyArea (display, erase_circ, pix, draw_board, 0, 0,
block_width, block_height,
(move.column * block_width), row_start);
XFillArc (display, pix, draw_circ, (move.column * block_width) +
line_width / 2
,(move.row * block_height) + line_width / 2, block_width
- line_width + 1,
block_height - line_width + 1, 0, 360 * 64);
XCopyArea (display, pix, win, draw_board, (move.column * block_width),
(move.row * block_height) - anim, block_width, block_height + anim,
(move.column * block_width), (move.row * block_height) - anim);
XFlush (display);
}
return 0;
}
/****************************************************************************/
/*
* tell user that move was bad
*/
int
X_bad_move ()
{
XBell (display, 100);
XFlush (display);
return 0;
}
/****************************************************************************/
/*
* indicate game is over
*/
int
X_game_end (int winner, coord start, coord end)
{
game_over = True;
win_start = start;
game_winner = winner;
win_end = end;
win_start.row++;
win_start.column++;
win_end.row++;
win_end.column++;
draw_final ();
return 0;
}
/***************************************************************************/
/*
* handle expose and resize events
*/
int
X_handle_events ()
{
XEvent event;
int cnt;
char buf[5];
KeySym keysym;
while (XPending (display) > 0)
{
XNextEvent (display, &event);
switch (event.type)
{
case KeyPress:
cnt = XLookupString (&event.xkey, buf, 1, &keysym, NULL);
if (buf[0] == 'q' || buf[0] == 'Q')
return QUIT;
break;
case ConfigureNotify:
if (allocated == True)
resize (event.xconfigure.width, event.xconfigure.height);
else
{
width = event.xconfigure.width;
height = event.xconfigure.height;
}
break;
case Expose:
if (allocated == True)
XCopyArea (display, pix, win, draw_board, event.xexpose.x,
event.xexpose.y, event.xexpose.width, event.xexpose.height,
event.xexpose.x, event.xexpose.y);
else
{
XClearWindow (display, win);
XDrawString (display, win, open_text, width / 2 - XTextWidth (the_font,
TITLE_STRING, strlen (TITLE_STRING)), height / 2, TITLE_STRING,
strlen (TITLE_STRING));
}
XFlush (display);
break;
default:
break;
}
}
return 0;
}
/***********************************************************************/
/*
* change player list to indicate whose turn it is
*/
int
X_show_turn (int player_no)
{
players_turn = player_no;
list_players ();
XCopyArea (display, pix, win, draw_board, block_width,
game_attrib.num_rows * block_height,
width, block_height * 2, block_width,
game_attrib.num_rows * block_height);
}
/***************************************************************************/
/*internal subroutines*******************************************************/
/****************************************************************************/
/*
* set block width, height
*/
void
set_block_size ()
{
block_width = width / (game_attrib.num_columns + 2);
if (block_width < 1)
block_width = 1;
block_height = height / (game_attrib.num_rows + 3);
if (block_height < 1)
block_height = 1;
line_width = block_width / 10;
if (line_width < 1)
line_width = 1;
if (line_width % 2 == 0)
line_width++;
}
/****************************************************************************/
/*
* create the pixmaps
*/
void
create_pixmaps ()
{
/* create Pixmaps */
pix = XCreatePixmap (display, win, width, height,
DefaultDepth (display, screen_num));
erase_circ = XCreatePixmap (display, win, block_width,
block_height, DefaultDepth (display, screen_num));
}
/*************************************************************************/
/*
* create GCs
*/
void
create_gcs ()
{
XGCValues gc_values;
/* create GCs */
gc_values.foreground = foreground;
gc_values.background = 0;
gc_values.line_width = line_width;
gc_values.join_style = JoinMiter;
gc_values.graphics_exposures = False;
draw_board = XCreateGC (display, pix, GCForeground | GCBackground
| GCLineWidth | GCJoinStyle
| GCGraphicsExposures, &gc_values);
gc_values.font = the_font->fid;
draw_text = XCreateGC (display, pix, GCForeground | GCBackground |
GCFont | GCGraphicsExposures, &gc_values);
draw_circ = XCreateGC (display, pix, 0, NULL);
gc_values.foreground = background;
gc_values.background = 0;
clear_board = XCreateGC (display, pix, GCForeground |
GCBackground | GCGraphicsExposures, &gc_values);
gc_values.foreground = shadow;
draw_shadow = XCreateGC (display, pix, GCForeground | GCBackground
| GCLineWidth | GCJoinStyle | GCGraphicsExposures,
&gc_values);
}
/*************************************************************************/
/*
* create the board
*/
void
make_board ()
{
int row_start, col_start, i;
int offset, num = 0;
XSegment shad[MAX_ROW + MAX_COL + 2], board[MAX_ROW + MAX_COL + 2];
offset = line_width;
/* clear board */
XFillRectangle (display, pix, clear_board, 0, 0, width, height);
/*build the board */
/*rectangles extend one past block */
num = 0;
for (col_start = block_width; col_start / block_width <=
(game_attrib.num_columns + 1); col_start = col_start + block_width)
{
shad[num].x1 = col_start - offset;
shad[num].y1 = block_height + offset - (line_width / 2);
shad[num].x2 = col_start - offset;
shad[num].y2 = ((game_attrib.num_rows + 1) * block_height) +
offset + (line_width / 2);
board[num].x1 = col_start;
board[num].y1 = block_height - (line_width / 2);
board[num].x2 = col_start;
board[num++].y2 = (game_attrib.num_rows + 1) * block_height
+ (line_width / 2);
}
for (row_start = block_height; row_start / block_height
<= (game_attrib.num_rows + 1); row_start = row_start + block_height)
{
shad[num].x1 = block_width - offset - (line_width / 2);
shad[num].y1 = row_start + offset;
shad[num].x2 = ((game_attrib.num_columns + 1) * block_width)
- offset + (line_width / 2);
shad[num].y2 = row_start + offset;
board[num].x1 = block_width - (line_width / 2);
board[num].y1 = row_start;
board[num].x2 = (game_attrib.num_columns + 1) * block_width +
(line_width / 2);
board[num++].y2 = row_start;
}
XDrawSegments (display, pix, draw_shadow, shad, num);
XDrawSegments (display, pix, draw_board, board, num);
list_players ();
XCopyArea (display, pix, win, draw_board, 0, 0, width, height, 0, 0);
}
/****************************************************************************/
/*
* change color of circles drawn
*/
void
change_color (int fg, int bg, GC change)
{
XGCValues gc_values;
gc_values.foreground = fg;
gc_values.background = bg;
XChangeGC (display, change, GCForeground | GCBackground, &gc_values);
}
/***************************************************************************/
/*
* draw move selection on top of board
*/
void
draw_move (coord new_pos, coord old_pos)
{
/* erase old position */
if (old_pos.row != -1 && old_pos.column != -1)
XCopyArea (display, erase_circ, pix, draw_board, 0, 0,
block_width, block_height,
(old_pos.column * block_width), (old_pos.row * block_height));
/* draw new position */
if (new_pos.row != -1 && new_pos.column != -1)
{
XCopyArea (display, pix, erase_circ, draw_board,
(new_pos.column * block_width), (new_pos.row * block_height),
block_width, block_height, 0, 0);
XFillArc (display, pix, draw_circ, (new_pos.column * block_width)
+ line_width / 2, (new_pos.row * block_height) + line_width / 2,
block_width - line_width + 1,
block_height - line_width + 1, 0, 360 * 64);
}
/* copy to window */
if (old_pos.row != -1 && old_pos.column != -1)
XCopyArea (display, pix, win, draw_board, (old_pos.column * block_width),
(old_pos.row * block_height), block_width, block_height,
(old_pos.column * block_width), (old_pos.row * block_height));
if (new_pos.row != -1 && new_pos.column != -1)
XCopyArea (display, pix, win, draw_board, (new_pos.column * block_width),
(new_pos.row * block_height), block_width, block_height,
(new_pos.column * block_width), (new_pos.row * block_height));
XFlush (display);
}
/****************************************************************************/
/*
* draw indication of winner
*/
void
draw_final ()
{
coord win_pos;
int wait;
XEvent event;
char winner_str[80];
win_pos.row = game_attrib.num_rows + 2;
win_pos.column = 1;
if (game_winner < 0)
XDrawString (display, pix, draw_text, ((win_pos.column) * block_width),
((win_pos.row + 1) * block_height) - block_height / 4,
(game_winner == -1 ? TIE_STRING : CANCEL_STRING),
(game_winner == -1 ? strlen (TIE_STRING) :
strlen (CANCEL_STRING)));
else
{
/* draw line connecting winning pieces on pixmap and window*/
XDrawLine (display, win, draw_board, (win_start.column * block_width)
+ (block_width / 2),
(win_start.row * block_height) + (block_height / 2),
(win_end.column * block_width) + (block_width / 2),
(win_end.row * block_height) + (block_height / 2));
XDrawLine (display, pix, draw_board, (win_start.column * block_width)
+ (block_width / 2),
(win_start.row * block_height) + (block_height / 2),
(win_end.column * block_width) + (block_width / 2),
(win_end.row * block_height) + (block_height / 2));
change_color (player_pixels[game_winner - 1], background, draw_text);
sprintf (winner_str, "%s%s", game_attrib.players[game_winner - 1],
WINNER_STRING);
XDrawString (display, pix, draw_text, ((win_pos.column) *
block_width), ((win_pos.row + 1) * block_height)
- block_height / 4, winner_str, strlen (winner_str));
}
/* copy text area to window */
XCopyArea (display, pix, win, draw_board, (win_pos.column * block_width),
(win_pos.row * block_height),
width, block_height, (win_pos.column * block_width),
(win_pos.row * block_height));
XFlush (display);
}
/***************************************************************************/
/*
* x coordinate to column number
*/
coord
get_cursor_pos (int x, int y)
{
coord pos;
pos.column = x / block_width;
pos.row = y / block_height;
if (pos.column == 0 || (pos.column > game_attrib.num_columns))
pos.column = -1;
if (game_attrib.game_type == GRAVITY)
pos.row = 0;
else if (pos.row == 0 || (pos.row > game_attrib.num_rows))
pos.row = -1;
return pos;
}
/****************************************************************************/
void
free_pixmaps ()
{
XFreePixmap (display, pix);
XFreePixmap (display, erase_circ);
}
/*****************************************************************************/
void
free_gcs ()
{
XFreeGC (display, draw_board);
XFreeGC (display, clear_board);
XFreeGC (display, draw_text);
XFreeGC (display, draw_circ);
XFreeGC (display, draw_shadow);
}
/**************************************************************************/
/*
* draw a piece into pixmap
*/
void
draw_piece (int row, int col, int pixel)
{
change_color (pixel, background, draw_circ);
XFillArc (display, pix, draw_circ, (col * block_width)
+ line_width / 2, (row * block_height) + line_width / 2,
block_width - line_width + 1,
block_height - line_width + 1, 0, 360 * 64);
}
/****************************************************************************/
/*
* resize the window
*/
void
resize (int w, int h)
{
int i, j;
XGCValues values;
int old_line_width;
/* only handle resize */
if (w != width || h != height)
{
/* make sure new size is big enough */
if ((w >= ((line_width + 1) * (game_attrib.num_columns + 2)))
&& (h >= ((line_width + 1) * (game_attrib.num_rows + 3))))
{
width = w;
height = h;
old_line_width = line_width;
set_block_size ();
XFreeFont (display, the_font);
load_font ();
values.font = the_font->fid;
XChangeGC (display, draw_text, GCFont, &values);
if (line_width != old_line_width)
{
values.line_width = line_width;
XChangeGC (display, draw_board, GCLineWidth, &values);
XChangeGC (display, draw_shadow, GCLineWidth, &values);
}
free_pixmaps ();
create_pixmaps ();
make_board ();
/*redraw already placed game pieces */
for (i = 0; i < game_attrib.num_rows; i++)
for (j = 0; j < game_attrib.num_columns; j++)
if (the_board[i][j] != 0)
draw_piece (i + 1, j + 1, player_pixels[the_board[i][j] - 1]);
if (game_over == True)
draw_final ();
/*expose will come after a resize */
}
}
}
/*****************************************************************************/
char *
get_resource (char *resource)
{
char name[50];
char *str_type[20];
XrmValue xval;
sprintf (name, "%s.%s", program_name, resource);
if (!XrmGetResource (dbase, name, NULL, str_type, &xval))
{
printf ("resource (%s) not found\n", resource);
return NULL;
}
return xval.addr;
}
/****************************************************************************/
int
get_color (char *name)
{
Colormap cmap;
XColor def;
cmap = DefaultColormap (display, screen_num);
if (!XParseColor (display, cmap, name, &def))
{
printf ("color (%s) not found\n", name);
return BlackPixel (display, screen_num);
}
XAllocColor (display, cmap, &def);
return def.pixel;
}
/*************************************************************************/
void
get_home_dir (char *dest)
{
struct passwd *pInfo;
pInfo = getpwuid (getuid ());
strcpy (dest, pInfo->pw_dir);
}
/*****************************************************************************/
void
list_players ()
{
int x, y, i;
char the_player[NAME_SIZE + 1];
x = block_width;
y = ((game_attrib.num_rows + 2) * block_height) - block_height / 4;
for (i = -1; i < game_attrib.num_players; i++)
{
change_color ((i == -1) ? foreground : player_pixels[i],
(i == (players_turn - 1)) ? highlight : background,
draw_text);
sprintf (the_player, "%s", (i == -1) ? PLAYER_STRING :
game_attrib.players[i]);
XDrawImageString (display, pix, draw_text, x, y,
the_player, strlen (the_player));
x = x + XTextWidth (the_font, the_player, strlen (the_player));
XDrawString (display, pix, draw_text, x, y, " ", 1);
x = x + XTextWidth (the_font, " ", 1);
}
/* change color back */
change_color (player_pixels[game_attrib.your_number - 1], background,
draw_text);
}
/*****************************************************************************/
void
load_font ()
{
int res_x, res_y, pixels;
char font_string[100];
res_x = DisplayWidth (display, screen_num) / (DisplayWidthMM (display,
screen_num) / 25.4);
res_y = DisplayHeight (display, screen_num) / (DisplayHeightMM (display,
screen_num) / 25.4);
pixels = block_height / 2;
sprintf (font_string, "-*-helvetica-bold-*-*-*-%d-*-%d-%d-*-*-*-*",
pixels, res_x, res_y);
the_font = XLoadQueryFont (display, font_string);
PRINTF (("%s %d\n", font_string, the_font));
if (the_font == 0)
the_font = XLoadQueryFont (display, "9x15");
}
/*****************************************************************************/
/*
* draw the timer
*/
void
draw_clock (time_t tleft)
{
char time_str[20];
int x, y, len;
x = block_width;
y = (game_attrib.num_rows + 3) * block_height - (block_height / 4);
len = XTextWidth (the_font, TIME_STRING, strlen (TIME_STRING));
if (tleft != -1)
{
/* erase old time */
XClearArea (display, win, x + len, y - block_height / 2, width - (x + len),
block_height, False);
/* draw new time */
sprintf (time_str, "%s%d ", TIME_STRING, tleft);
XDrawImageString (display, win, draw_text, x, y, time_str,
strlen (time_str));
}
else
XClearArea (display, win, x, y - block_height / 2, width, block_height, False);
}